package com.zds.hj.poseidon.biz.common.helper;

import com.google.common.collect.Lists;
import com.zds.boot.common.context.ZDSContext;
import com.zds.boot.common.exception.BusinessException;
import com.zds.boot.common.utils.Dates;
import com.zds.boot.common.utils.Ids;
import com.zds.boot.common.utils.Reflections;
import com.zds.component.files.facade.dto.FileAuthDto;
import com.zds.component.files.facade.dto.FilesResult;
import com.zds.component.files.facade.dto.FilesUploadReqDto;
import com.zds.hj.competency.facade.enums.TencentApiTypeEnum;
import com.zds.hj.competency.facade.mapping.dto.syxapi.ocr.*;
import com.zds.hj.icmc.facade.dto.file.FileTransAndOcrReqDto;
import com.zds.hj.icmc.facade.dto.file.FileUploadResultDto;
import com.zds.hj.poseidon.biz.common.CompetencyServiceInterface;
import com.zds.hj.poseidon.biz.common.FileServiceInterface;
import com.zds.user.facade.pbac.enums.UserTypeEnum;
import com.zds.zly.common.utils.EmptyChecker;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @Author duanhao
 * @Description 文件上传并识别
 * @Date 2023/06/08 15:13
 */
@Slf4j
@Service
public class FileUploadTransService {

    @Resource
    private FileServiceInterface fileServiceInterface;
    @Resource
    private CompetencyServiceInterface competencyServiceInterface;

    /**
     * 文档附件上传
     * 1，上传到obsId
     * 2，上传腾讯ocr识别
     * 3, 返回识别结果
     *
     * @param request 识别类型，上传的文件
     * @return`
     */
    public FileUploadResultDto fileTransFromObs(HttpServletRequest request) {
        // 识别类型 参照：TencentApiTypeEnum
        String type = request.getParameter("type");
        // 上传的文件
        MultipartFile multipartFile = ((MultipartHttpServletRequest) request).getFile("file");
        FileUploadResultDto fileUploadResultDto = fileTransFromObs(type, multipartFile);
        handleSpace(fileUploadResultDto);
        return fileUploadResultDto;
    }

    /**
     * @param info :
     * @return void
     * @Author jingyh
     * @Description 处理空格
     **/
    private void handleSpace(FileUploadResultDto info) {
        if (info == null) {
            return;
        }
        Set<Field> fields = Reflections.getFields(info.getClass());
        for (Field field : fields) {
            Object fieldValue = Reflections.getFieldValue(info, field);
            if (fieldValue != null && fieldValue instanceof String) {
                Reflections.setFieldValue(info, field, fieldValue.toString().trim());
            }
        }
    }

    /**
     * 获取上传文件中的文件信息
     *
     * @param multipartFile 文件流
     * @return
     */
    private FilesUploadReqDto getUploadFile(MultipartFile multipartFile) {
        byte[] bytes = null;
        try {
            bytes = multipartFile.getBytes();
        } catch (IOException e) {
            log.error("获取文件发生流异常", e);
            e.printStackTrace();
        }
        FilesUploadReqDto file = new FilesUploadReqDto();
        String fileName = multipartFile.getOriginalFilename();
        file.setByteData(bytes);
        file.setFileName(fileName);
        return file;
    }

    public FileUploadResultDto fileTransFromObs(String type, MultipartFile multipartFile) {
        FileTransAndOcrReqDto reqDto = new FileTransAndOcrReqDto();
        //1，上传到obsId
        reqDto.setType(type);
        log.info("图片附件上传开始，入参-->>{}", type);
        FilesUploadReqDto uploadFile = getUploadFile(multipartFile);
        List<String> ocrTypeList = Lists.newArrayList(TencentApiTypeEnum.OCR_BIZ_LICENSE.code(), TencentApiTypeEnum.OCR_ID_CARD.code(), TencentApiTypeEnum.OCR_ID_CARD_B.code());
        if (ocrTypeList.contains(type) && (uploadFile.getByteData().length / 1024) > 5120) {
            throw new BusinessException("图片过大");
        }
        log.info("上传图片大小：{}kb", uploadFile.getByteData().length / 1024);
        String fileName = uploadFile.getFileName();
        String fileType = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
        List<String> supportFileTypeList = Lists.newArrayList("jpg", "png", "jpeg");
        //营业执照识别时 如果上传的是非jpg、png、jpeg格式
        if (EmptyChecker.notEmpty(fileType) && !supportFileTypeList.contains(fileType)) {
            log.error("上传图片无法识别，原始文件名-->>{}", fileName);
            throw new BusinessException("上传图片无法识别");
        }
        FileUploadResultDto fileUploadResultDto = handlerOcr(uploadFile.getByteData(), type);
        Long obsId = handleObs(uploadFile.getByteData(), uploadFile.getFileName(), type, fileType);
        if (obsId != null) {
            fileUploadResultDto.setFileId(obsId.toString());
        }
        log.info("图片附件上传成功");
        log.info("图片附件上传结束<<--{}", fileUploadResultDto);
        return fileUploadResultDto;
    }


    /**
     * 获取处理后的结果
     *
     * @param content
     * @param type
     * @return
     */
    private FileUploadResultDto handlerOcr(byte[] content, String type) {
        FileUploadResultDto resultDto = null;
        FileTransAndOcrReqDto reqDto = new FileTransAndOcrReqDto();
        reqDto.setType(type);
        reqDto.setContent(content);
        resultDto = uploadToOcr(reqDto);
        //如果是身份证反面识别，校验有效期
        if (TencentApiTypeEnum.OCR_ID_CARD_B.code().equals(type) && EmptyChecker.notEmpty(resultDto.getValidDate())) {
            String validDate = resultDto.getValidDate();
            //获取身份证时间
            String endDateStr;
            try {
                endDateStr = validDate.split("-")[1];
            } catch (Exception e) {
                throw new BusinessException("文件无法识别，请重新上传！");
            }
            if ("长期".equals(endDateStr)) {
                return resultDto;
            }
            Date endDate = Dates.stringToDate(endDateStr, "yyyy.MM.dd");
            if (EmptyChecker.isEmpty(endDate)) {
                throw new BusinessException("文件无法识别，请重新上传！");
            }

            //获取当前时间 大于最后日期
            if (Dates.formatToYMDDate(new Date()).compareTo(endDate) > 0) {
                throw new BusinessException("身份证已过期，请重新上传");
            }
        }
        return resultDto;
    }

    /**
     * 文件上传到文件服务器
     *
     * @param bytes
     * @param fileName
     * @param type
     * @param fileType
     * @return
     */
    private Long handleObs(byte[] bytes, String fileName, String type, String fileType) {
        if (!type.equals("OCR_BANK_CARD")) {
            ZDSContext.SeUserInfo seUserInfo = ZDSContext.get().getSeUserInfo();
            if (seUserInfo == null) {
                throw new BusinessException("用户登录信息不存在");
            }
            FileAuthDto authDto = FileAuthDto.builder().buildUserId(seUserInfo.getId()).buildUserType(UserTypeEnum.PLATFORM.code()).build();
            if (EmptyChecker.isEmpty(fileName)) {
                fileName = Ids.gid() + fileType;
            }
            FilesResult obsResult = fileServiceInterface.put(bytes, fileName, authDto);
            return obsResult.getObsId();
        }
        return null;
    }

    /**
     * 上传金融机构文档服务器
     * 营业执照号，身份证号
     * ocr识别
     *
     * @param reqDto
     * @return FileUploadRespDto
     */
    public FileUploadResultDto uploadToOcr(FileTransAndOcrReqDto reqDto) {
        byte[] content = reqDto.getContent();
        String type = reqDto.getType();
        log.info("上传附件开始，类型-->>{}", type);
        if (content == null) {
            throw new BusinessException("附件不能为空");
        }
        FileUploadResultDto respDto = new FileUploadResultDto();
        try {
            log.info("上传附件成功");
            respDto = tencentOcr(content, type, respDto);
        } catch (BusinessException e) {
            log.info("识别异常：{}", e);
            throw new BusinessException("识别异常");
        }
        log.info("上传附件结束<<--{}", respDto);
        return respDto;
    }

    /**
     * 调用识别，并处理返回参数
     * @param file
     * @param type
     * @param respDto
     * @return
     */
    private FileUploadResultDto tencentOcr(byte[] file, String type, FileUploadResultDto respDto) {
        log.info("进入ocr识别类型：{}", type);
        Long startTime = System.currentTimeMillis();
        Long endTime = System.currentTimeMillis();
        log.info("结束ocr识别消耗时间：{}", endTime - startTime);
        //营业执照识别
        if (TencentApiTypeEnum.OCR_BIZ_LICENSE.code().equals(type)) {
            OcrDistingReqDto distingReqDto = new OcrDistingReqDto();
            distingReqDto.setBase64File(Base64.encodeBase64String(file));
            OcrDistingEnterpriseRespDto ocrDistingRespDto = competencyServiceInterface.ocrBizLicence(distingReqDto);
            if (EmptyChecker.isEmpty(ocrDistingRespDto)) {
                throw new BusinessException("企业营业执照无法识别，重新上传！");
            }
            String busiLicNo = ocrDistingRespDto.getCreditCode();
            String entName = ocrDistingRespDto.getEnterpriseName();
            String zlyAddress = ocrDistingRespDto.getAddress();
            String legelPerson = ocrDistingRespDto.getLegelPerson();
            respDto.setName(entName);
            respDto.setPicNo(busiLicNo);
            respDto.setApplyAddressDetail(zlyAddress);
            respDto.setLegelPerson(legelPerson);
            respDto.setType("B");
            // 身份证正面识别
        } else if (TencentApiTypeEnum.OCR_ID_CARD.code().equals(type)) {
            OcrDistingIDCardReqDto reqDto = new OcrDistingIDCardReqDto();
            reqDto.setBase64File(Base64.encodeBase64String(file));
            reqDto.setIsFrontSide(Boolean.TRUE);
            OcrDistingIDCardRespDto ocrDistingRespDto = competencyServiceInterface.ocrIdCard(reqDto);
            log.info("身份证正面识别结果：{}", ocrDistingRespDto);
            respDto.setName(ocrDistingRespDto.getName());
            respDto.setPicNo(ocrDistingRespDto.getIdNo());
            respDto.setApplyAddressDetail(ocrDistingRespDto.getAddress());
            respDto.setType("P");
            // 身份证反面识别
        } else if (TencentApiTypeEnum.OCR_ID_CARD_B.code().equals(type)) {
            OcrDistingIDCardReqDto reqDto = new OcrDistingIDCardReqDto();
            reqDto.setBase64File(Base64.encodeBase64String(file));
            reqDto.setIsFrontSide(Boolean.FALSE);
            OcrDistingIDCardRespDto ocrDistingRespDto = competencyServiceInterface.ocrIdCard(reqDto);
            log.info("身份证反面识别结果：{}", ocrDistingRespDto);
            respDto.setValidDate(ocrDistingRespDto.getValidDate());
            respDto.setType("P");
            // 银行卡识别
        } else if (TencentApiTypeEnum.OCR_BANK_CARD.code().equals(type)) {
            OcrDistingReqDto reqDto = new OcrDistingReqDto();
            reqDto.setBase64File(Base64.encodeBase64String(file));
            OcrDistingBankCardRespDto cardRespDto = competencyServiceInterface.ocrBankCard(reqDto);
            log.info("银行卡识别结果：{}", cardRespDto);
            if (cardRespDto == null) {
                throw new BusinessException("银行卡识别结果为空");
            }
            respDto.setPicNo(cardRespDto.getBankCardNo());
            respDto.setType("C");
        } else {
            throw new BusinessException("暂不支持其他类型ocr识别");
        }
        return respDto;
    }


}
